/**
 *******************************************************************************
 * @brief       Character LCD driver (PAL_HD44780).
 * 
 * @author      Ashwin Vijayakumar
 * 
 * @file        PalHd44780.c
 * 
 * @version
 * 
 * @date        Feb 1, 2012 10:30:00 PM
 * 
 * @details     Provide a detailed description of the module here (Multi-line).
 * 
 * @pre         Mention any preconditions required to use this module.
 * 
 * @bug         List any bugs in this module.
 * 
 * @note        List any odd modes while using this module.
 * 
 * @warning     List any warnings against using the objects of this module.
 *******************************************************************************
 * @copyright 2012
 * <a href="http://www.afflatustech.com">Afflatus Techtronics</a>
 * and <a href="http://www.ashwinvijayakumar.co.nr">Ashwin Vijayakumar</a>
 * @n@n
 * This work is licensed under the Creative Commons
 * Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a copy
 * of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or
 * send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain
 * View, California, 94041, USA.
 *******************************************************************************
 */

/**@cond -----------------------------------------------------------------------
 * Includes section
 * Add all #include here.
 * ----------------------------------------------------------------- @endcond */

/**@cond System headers -------------------------------------------- @endcond */

/**@cond Local headers --------------------------------------------- @endcond */
#include "PalHd44780.h"
#include "PalHd44780_Fonts.h"
#include "Soft_Delay.h"

/**@cond -----------------------------------------------------------------------
 * typedef section (File scope)
 * Add typedef's with file scope here.
 * Capitalization: Upper_Camel_Case.
 * Declare typedef's with project scope in PalHd44780.h.
 * ----------------------------------------------------------------- @endcond */

/**@cond -----------------------------------------------------------------------
 * Constants section (File scope)
 * Add all constants with file scope here.
 * Capitalization: ALL_CAPS.
 * Note that all constants listed here are limited to this file scope.
 * For project wide scope, declare constants in PalHd44780.h.
 * ----------------------------------------------------------------- @endcond */

#define PAL_HD44780_ONE_LINE             0
#define PAL_HD44780_TWO_LINE             1

#define PAL_HD44780_5x8_FONT             0
#define PAL_HD44780_5x10_FONT            1

/**@cond -----------------------------------------------------------------------
 * Macros section (File scope)
 * Add all macros with file scope here.
 * Capitalization: ALL_CAPS.
 * Note that all macros listed here are limited to this file scope.
 * For project wide scope, declare macros in PalHd44780.h.
 * ----------------------------------------------------------------- @endcond */

#define PAL_HD44780_DELAY_NS(X)          delay_ns((uint16_t)X)
#define PAL_HD44780_DELAY_US(X)          delay_us((uint16_t)X)
#define PAL_HD44780_DELAY_MS(X)          delay_ms((uint16_t)X)

/**@cond -----------------------------------------------------------------------
 * Global variables section (File scope)
 * Add global variables with file scope here. 
 * Capitalization: lower_case.
 * Declare them with 'static' keyword.
 * ----------------------------------------------------------------- @endcond */

static uint8_t PalHd44780_Row_Addr[PAL_HD44780_NO_OF_ROWS] = {
    (0x80 | PAL_HD44780_ROW0_FIRST_COLUMN),
    (0x80 | PAL_HD44780_ROW1_FIRST_COLUMN)
#if(PAL_HD44780_NO_OF_ROWS > 2)
    ,
    (0x80 | PAL_HD44780_ROW2_FIRST_COLUMN),
    (0x80 | PAL_HD44780_ROW3_FIRST_COLUMN)
#endif
};

/**@cond -----------------------------------------------------------------------
 * Global variables section (Project scope)
 * PROJECT SCOPE G-VARIABLES ARE LIKE FORBIDDEN FRUIT. REFRAIN FROM USING THEM,
 * DECLARE FILE SCOPE G-VARIABLES INSTEAD AND DEFINE GETTER/SETTER METHODS TO
 * ACCESS THEM.
 * Add global variables with project scope here.
 * Capitalization: lower_case.
 * Declare them without 'static' keyword.
 * Also declare these variables in hd44780.h with 'extern' keyword.
 * ----------------------------------------------------------------- @endcond */

/**@cond -----------------------------------------------------------------------
 * Function prototypes section (File scope)
 * Add prototypes for all functions with file scope here. 
 * Capitalization: lower_Camel_Case.
 * Declare them with 'static' keyword.
 * For functions with project scope, declare the function prototype in 
 * hd44780.h without 'static' keyword.
 * ----------------------------------------------------------------- @endcond */

/**@cond -----------------------------------------------------------------------
 * Getter/setter method section (Project scope)
 * Define getter/setter methods to provide project scope global access to file 
 * scope global variables. (AVOID USING THESE IF YOU HAVE THROUGHPUT ISSUES).
 * Capitalization: get_Camel_Case/is_Camel_Case/set_Camel_Case.
 * Declare the prototype for these functions in hd44780.h. 
 * ----------------------------------------------------------------- @endcond */

Std_BoolType
is_PalHd44780_Busy(uint8_t time_out)
{
  Std_BoolType retVal = TRUE;

  do
    {
      retVal = ((PalHd44780_ByteRead(PAL_HD44780_INS) & 0x80) ? TRUE : FALSE);
    } while((retVal == TRUE) && (--time_out));

  return(retVal);
}

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      none.
 * @param       An 8-Bit variable containing a valid upper nibble (4-Bit data
 *              to be written on the LCD's data port).
 * @author      Ashwin
 * @date        Feb 4, 2012, 4:18:02 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

static void
PalHd44780_NibbleWrite(uint8_t nib)
{
#if(8 == MCALGPIO_WIDTH)
  uint8_t temp_msk = 0x0F;
  uint8_t temp_nib = nib;
#elif(16 == MCALGPIO_WIDTH)
  uint16_t temp_msk = 0x000F;
  uint16_t temp_nib = (0x0000 | nib);
#elif(32 == MCALGPIO_WIDTH)
  uint32_t temp_msk = 0x0000000F;
  uint32_t temp_nib = (0x00000000 | nib);
#endif /* (8 == MCALGPIO_WIDTH) */

  /* Instruction write as an internal operation */
  McalGpio_ResetPins(PAL_HD44780_CTRL_PORT, (PAL_HD44780_RS | PAL_HD44780_RW));

  /* Clear LCD's data port and then load byte */
  McalGpio_ResetPins(PAL_HD44780_DATA_PORT, (temp_msk << PAL_HD44780_DATA_POSITION));
  McalGpio_SetPins(PAL_HD44780_DATA_PORT, (((temp_nib >> 4) & temp_msk) << PAL_HD44780_DATA_POSITION));

  /* EN Pulse */
  PAL_HD44780_DELAY_NS(60);                                 /* tAS */
  McalGpio_SetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_EN);
  PAL_HD44780_DELAY_NS(450);                                /* PWeh */
  McalGpio_ResetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_EN);
  //PAL_HD44780_DELAY_NS(10);                                 /* tAH */
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          void PalHd44780_CMDW(uint8_t cmd)
 * @return      none.
 * @param       Byte to be written to the LCD's data port.
 * @param       PAL_HD44780_INS = Instruction, PAL_HD44780_DAT = Data
 * @author      Ashwin
 * @date        Feb 4, 2012, 11:32:02 AM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalHd44780_ByteWrite(uint8_t byt, PalHd44780_ByteType bytType)
{
  Std_ReturnType retVal = E_NOT_OK;

#if(8 == PAL_HD44780_DATA_LEN)
  /* 8-Bit mode */
#if(8 == MCALGPIO_WIDTH)
  uint8_t temp_msk = 0xFF;
  uint8_t temp_byt = byt;
#elif(16 == MCALGPIO_WIDTH)
  uint16_t temp_msk = 0x00FF;
  uint16_t temp_byt = (0x0000 | byt);
#elif(32 == MCALGPIO_WIDTH)
  uint32_t temp_msk = 0x000000FF;
  uint32_t temp_byt = (0x00000000 | byt);
#endif /* (8 == MCALGPIO_WIDTH) */

#elif(4 == PAL_HD44780_DATA_LEN)
  /* 4-Bit mode */
#if(8 == MCALGPIO_WIDTH)
  uint8_t temp_msk = 0x0F;
  uint8_t temp_byt = byt;
#elif(16 == MCALGPIO_WIDTH)
  uint16_t temp_msk = 0x000F;
  uint16_t temp_byt = (0x0000 | byt);
#elif(32 == MCALGPIO_WIDTH)
  uint32_t temp_msk = 0x0000000F;
  uint32_t temp_byt = (0x00000000 | byt);
#endif /* (8 == MCALGPIO_WIDTH) */

#endif /* (8 == PAL_HD44780_DATA_LEN) */

  if(PAL_HD44780_INS == bytType)
    { /* Instruction write as an internal operation */
      McalGpio_ResetPins(PAL_HD44780_CTRL_PORT, (PAL_HD44780_RS | PAL_HD44780_RW));
      retVal = E_OK;
    }
  else if(PAL_HD44780_DAT == bytType)
    { /* Data write as an internal operation */
      McalGpio_SetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_RS);
      McalGpio_ResetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_RW);
      retVal = E_OK;
    }
  /* else not required (PAL_HD44780_INS == bytType) */

  if(E_OK == retVal)
    {
#if(8 == PAL_HD44780_DATA_LEN)                              /* 8-Bit mode */

      /* Clear LCD's data port and then load byte */
      McalGpio_ResetPins(PAL_HD44780_DATA_PORT, (temp_msk << PAL_HD44780_DATA_POSITION));
      McalGpio_SetPins(PAL_HD44780_DATA_PORT, (temp_byt << PAL_HD44780_DATA_POSITION));

#elif(4 == PAL_HD44780_DATA_LEN)                            /* 4-Bit mode */
      /* ==== Write Upper Nibble ============================================ */

      /* Clear LCD's data port and then load byte */
      McalGpio_ResetPins(PAL_HD44780_DATA_PORT, (temp_msk << PAL_HD44780_DATA_POSITION));
      McalGpio_SetPins(PAL_HD44780_DATA_PORT, (((temp_byt >> 4) & temp_msk) << PAL_HD44780_DATA_POSITION));

      /* EN Pulse */
      PAL_HD44780_DELAY_NS(60);                                 /* tAS */
      McalGpio_SetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_EN);
      PAL_HD44780_DELAY_NS(450);                                /* PWeh */
      McalGpio_ResetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_EN);
      PAL_HD44780_DELAY_NS(10);                                 /* tAH */

      /* ==== Write Lower Nibble ============================================ */

      /* Clear LCD's data port and then load byte */
      McalGpio_ResetPins(PAL_HD44780_DATA_PORT, (temp_msk << PAL_HD44780_DATA_POSITION));
      McalGpio_SetPins(PAL_HD44780_DATA_PORT, ((temp_byt & temp_msk) << PAL_HD44780_DATA_POSITION));

#endif /* 8 == PAL_HD44780_DATA_LEN */

      /* EN Pulse */
      PAL_HD44780_DELAY_NS(60);                                 /* tAS */
      McalGpio_SetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_EN);
      PAL_HD44780_DELAY_NS(450);                                /* PWeh */
      McalGpio_ResetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_EN);
      PAL_HD44780_DELAY_NS(10);                                 /* tAH */
    }
  /* else not required (E_OK == retVal) */

  return(retVal);
}

/** End of PalHd44780_ByteWrite ******** Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          return_type function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 8, 2012, 7:14:09 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

uint8_t
PalHd44780_ByteRead(PalHd44780_ByteType bytType)
{
  uint8_t retVal = 0x00;

#if(8 == PAL_HD44780_DATA_LEN)
  /* 8-Bit mode */
#if(8 == MCALGPIO_WIDTH)
  uint8_t temp_msk = 0xFF;
  uint8_t temp_byt = 0x00;
#elif(16 == MCALGPIO_WIDTH)
  uint16_t temp_msk = 0x00FF;
  uint16_t temp_byt = 0x0000;
#elif(32 == MCALGPIO_WIDTH)
  uint32_t temp_msk = 0x000000FF;
  uint32_t temp_byt = 0x00000000;
#endif /* (8 == MCALGPIO_WIDTH) */

#elif(4 == PAL_HD44780_DATA_LEN)
  /* 4-Bit mode */
#if(8 == MCALGPIO_WIDTH)
  uint8_t temp_msk = 0x0F;
  uint8_t temp_byt = 0x00;
#elif(16 == MCALGPIO_WIDTH)
  uint16_t temp_msk = 0x000F;
  uint16_t temp_byt = 0x0000;
#elif(32 == MCALGPIO_WIDTH)
  uint32_t temp_msk = 0x0000000F;
  uint32_t temp_byt = 0x00000000;
#endif /* (8 == MCALGPIO_WIDTH) */

#endif /* (8 == PAL_HD44780_DATA_LEN) */

  if(PAL_HD44780_INS == bytType)
    { /* Instruction write as an internal operation */
      McalGpio_ResetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_RS);
      McalGpio_SetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_RW);
      retVal = E_OK;
    }
  else if(PAL_HD44780_DAT == bytType)
    { /* Data write as an internal operation */
      McalGpio_SetPins(PAL_HD44780_CTRL_PORT, (PAL_HD44780_RS | PAL_HD44780_RW));
      retVal = E_OK;
    }
  /* else not required (PAL_HD44780_INS == bytType) */

  if(E_OK == retVal)
    {
      McalGpio_SetPinDirection(PAL_HD44780_DATA_DIR, PAL_HD44780_DATA_PORT_MSK, GPIO_PIN_IN);

      /* EN Pulse */
      PAL_HD44780_DELAY_NS(60);                                 /* tAS */
      McalGpio_SetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_EN);
      PAL_HD44780_DELAY_NS(450);                                /* PWeh */

#if(8 == PAL_HD44780_DATA_LEN)                              /* 8-Bit mode */

      /* Clear LCD's data port and then load byte */
      temp_byt = McalGpio_ReadPins(PAL_HD44780_DATA_PORT, (temp_msk << PAL_HD44780_DATA_POSITION));
      retVal = temp_byt;

#elif(4 == PAL_HD44780_DATA_LEN)                            /* 4-Bit mode */
      /* ==== Write Upper Nibble ============================================ */

      /* Clear LCD's data port and then load byte */
      temp_byt = McalGpio_ReadPins(PAL_HD44780_DATA_PORT, (temp_msk << PAL_HD44780_DATA_POSITION));
      retVal = ((temp_byt >> PAL_HD44780_DATA_POSITION) << 4) & 0xF0;

      McalGpio_ResetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_EN);
      PAL_HD44780_DELAY_NS(10);                                 /* tAH */

      /* ==== Write Lower Nibble ============================================ */
      /* EN Pulse */
      PAL_HD44780_DELAY_NS(60);                                 /* tAS */
      McalGpio_SetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_EN);
      PAL_HD44780_DELAY_NS(450);                                /* PWeh */

      /* Clear LCD's data port and then load byte */
      temp_byt = McalGpio_ReadPins(PAL_HD44780_DATA_PORT, (temp_msk << PAL_HD44780_DATA_POSITION));
      retVal |= (temp_byt >> PAL_HD44780_DATA_POSITION) & 0x0F;

#endif /* 8 == PAL_HD44780_DATA_LEN */

      McalGpio_ResetPins(PAL_HD44780_CTRL_PORT, PAL_HD44780_EN);
      PAL_HD44780_DELAY_NS(10);                                 /* tAH */

      McalGpio_SetPinDirection(PAL_HD44780_DATA_DIR, PAL_HD44780_DATA_PORT_MSK, GPIO_PIN_OUT);
    }

  return(retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn           function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 12, 2012, 2:15:29 PM
 * @brief       Provide a brief description of the module here (Single line).
 * @details     Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalHd44780_LoadCGRAM(PalHd44780_FontPlotType *font_ptr, uint8_t cgram_addr)
{
  Std_ReturnType retVal = E_NOT_OK;
  uint8_t i = 8;

  is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
  PalHd44780_ByteWrite((0x40 | (cgram_addr & 0x3F)), PAL_HD44780_INS);

  while(i--)
    {
      is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
      PalHd44780_ByteWrite(*font_ptr++, PAL_HD44780_DAT);
    }

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 3, 2012, 11:07:53 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalHd44780_Init(PalHd44780_ConfigType* ConfigPtr)
{
  Std_ReturnType retVal = E_NOT_OK;

  /* Set I/O direction for pins connected to the LCD */
  McalGpio_SetPinDirection(PAL_HD44780_CTRL_DIR, PAL_HD44780_CTRL_PORT_MSK, GPIO_PIN_OUT);
  McalGpio_SetPinDirection(PAL_HD44780_DATA_DIR, PAL_HD44780_DATA_PORT_MSK, GPIO_PIN_OUT);

  /* Wait for more than 40ms after VCC rises to 2.7 V (15ms for 5V) */
  PAL_HD44780_DELAY_MS(40);

  /* Function set (Interface is 8 bits long.) */
  PalHd44780_NibbleWrite(0x30);

  /* Datasheet specified delay */
  PAL_HD44780_DELAY_MS(5);

  /* Function set (Interface is 8 bits long.) */
  PalHd44780_NibbleWrite(0x30);

  /* Datasheet specified delay */
  PAL_HD44780_DELAY_US(100);

  /* Function set (Interface is 8 bits long.) */
  PalHd44780_NibbleWrite(0x30);

  /* Function set (Set interface to be 4 bits long.) */
  PalHd44780_NibbleWrite(0x20);

  /* Function Set */
  PalHd44780_NibbleWrite(0x20);
  PalHd44780_NibbleWrite(((ConfigPtr->bit.lines << 7) | (ConfigPtr->bit.font << 6)));

  /* Display Control: Display ON and set Cursor+Blink */
  PalHd44780_NibbleWrite(0x00);
  PalHd44780_NibbleWrite((0xC0 | ((ConfigPtr->bit.cursor << 5) | (ConfigPtr->bit.blink << 4))));

  /* Display Clear */
  PalHd44780_NibbleWrite(0x00);
  PalHd44780_NibbleWrite(0x10);

  /* Entry Mode Set */
  PalHd44780_NibbleWrite(0x00);
  PalHd44780_NibbleWrite((0x40 | ((ConfigPtr->bit.increment << 5) | (ConfigPtr->bit.shift << 4))));

  return (retVal);
}

/** End of PalHd44780_Init ************* Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 16, 2012, 9:50:24 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalHd44780_Reconfig(PalHd44780_ConfigType* ConfigPtr, Std_BoolType clear_display)
{
  Std_ReturnType retVal = E_NOT_OK;

  /* Display Control: Display ON and set Cursor+Blink */
  PalHd44780_ByteWrite((0x0C | ((ConfigPtr->bit.cursor << 1) | (ConfigPtr->bit.blink))), PAL_HD44780_INS);

  if(TRUE == clear_display)
    {
      /* Display Clear */
      PalHd44780_ByteWrite(0x01, PAL_HD44780_INS);
    }
  /* else not required [(clear_display)] */

  /* Entry Mode Set */
  PalHd44780_ByteWrite((0x04 | ((ConfigPtr->bit.increment << 1) | (ConfigPtr->bit.shift))), PAL_HD44780_INS);

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          void function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 9, 2012, 7:58:29 AM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalHd44780_GoToXY(uint8_t row, uint8_t column)
{
  Std_ReturnType retVal = E_NOT_OK;

  if((row < PAL_HD44780_NO_OF_ROWS) && (column < PAL_HD44780_NO_OF_COLUMNS))
    {
      /* FIXME: Put a time out counter and return E_NOT_OK if it expires */
      is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
      PalHd44780_ByteWrite((PalHd44780_Row_Addr[row] + column), PAL_HD44780_INS);

      retVal = E_OK;
    }
  /* else not required [(row < PAL_HD44780_NO_OF_ROWS) && ....]*/

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          return_type function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 10, 2012, 7:58:15 AM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalHd44780_GetXY(uint8_t *X, uint8_t *Y)
{
  Std_ReturnType retVal = E_OK;
  uint8_t ddram_addr;

  ddram_addr = (PalHd44780_ByteRead(PAL_HD44780_INS) & ~0x80);

#if(PAL_HD44780_NO_OF_ROWS > 0)
  if((ddram_addr >= PAL_HD44780_ROW0_FIRST_COLUMN) &&
      (ddram_addr <= PAL_HD44780_ROW0_LAST_COLUMN))
    {
      *X = PAL_HD44780_LINE0;
      *Y = ddram_addr - PAL_HD44780_ROW0_FIRST_COLUMN;
    }
#if(PAL_HD44780_NO_OF_ROWS > 1)
  else if((ddram_addr >= PAL_HD44780_ROW1_FIRST_COLUMN) &&
      (ddram_addr <= PAL_HD44780_ROW1_LAST_COLUMN))
    {
      *X = PAL_HD44780_LINE1;
      *Y = ddram_addr - PAL_HD44780_ROW1_FIRST_COLUMN;
    }
#if(PAL_HD44780_NO_OF_ROWS > 2)
  else if((ddram_addr >= PAL_HD44780_ROW2_FIRST_COLUMN) &&
      (ddram_addr <= PAL_HD44780_ROW2_LAST_COLUMN))
    {
      *X = PAL_HD44780_LINE2;
      *Y = ddram_addr - PAL_HD44780_ROW2_FIRST_COLUMN;
    }
#if(PAL_HD44780_NO_OF_ROWS > 3)
  else if((ddram_addr >= PAL_HD44780_ROW3_FIRST_COLUMN) &&
      (ddram_addr <= PAL_HD44780_ROW3_LAST_COLUMN))
    {
      *X = PAL_HD44780_LINE3;
      *Y = ddram_addr - PAL_HD44780_ROW3_FIRST_COLUMN;
    }
#endif /* [(PAL_HD44780_NO_OF_ROWS > 0)] */
#endif /* [(PAL_HD44780_NO_OF_ROWS > 1)] */
#endif /* [(PAL_HD44780_NO_OF_ROWS > 2)] */
#endif /* [(PAL_HD44780_NO_OF_ROWS > 3)] */

  else
    {
      retVal = E_NOT_OK;
    }

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 9, 2012, 5:45:23 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

uint8_t
PalHd44780_WriteLine(uint8_t *S, uint8_t len, uint8_t line_no)
{
  uint8_t retVal = 0;
  uint8_t column_counter = 0;

  if(line_no < PAL_HD44780_NO_OF_ROWS)
    {
      /* FIXME: Put a time out counter and return E_NOT_OK if it expires */
      is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
      PalHd44780_ByteWrite(PalHd44780_Row_Addr[line_no], PAL_HD44780_INS);

      retVal = len;

      while(--retVal && *S)
        {
          is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
          PalHd44780_ByteWrite(*S++, PAL_HD44780_DAT);
        }

      /* In case len < PAL_HD44780_NO_OF_COLUMNS, clear the rest of the line */
      column_counter += (len - retVal);

      while(column_counter++ < PAL_HD44780_NO_OF_COLUMNS)
        {
          is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
          PalHd44780_ByteWrite(0x20, PAL_HD44780_DAT);
        }
    }
  else
    {
      len = 0;
    }

  return (len - retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/* Clear Line */
uint8_t
PalHd44780_ClearLine( uint8_t line_no )
{
  uint8_t column_counter = 0;

  /* Goto line number */
  is_PalHd44780_Busy( PAL_HD44780_BF_CHECK_TIMEOUT );
  PalHd44780_ByteWrite( PalHd44780_Row_Addr[line_no], PAL_HD44780_INS );

  while( column_counter++ < PAL_HD44780_NO_OF_COLUMNS )
    {
      is_PalHd44780_Busy( PAL_HD44780_BF_CHECK_TIMEOUT );
      PalHd44780_ByteWrite( ' ', PAL_HD44780_DAT );
    }

  /* Goto beginning line number */
  is_PalHd44780_Busy( PAL_HD44780_BF_CHECK_TIMEOUT );
  PalHd44780_ByteWrite( PalHd44780_Row_Addr[line_no], PAL_HD44780_INS );

  return( column_counter );
}

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          uint8_t function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 10, 2012, 6:47:56 AM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

uint8_t
PalHd44780_Puts(char *S)
{
  uint8_t retVal = 0;
  uint8_t current_addr;
  uint8_t row_counter, column_counter;

  PalHd44780_GetXY(&row_counter, &column_counter);

  while((row_counter < PAL_HD44780_NO_OF_ROWS) && *S)
    {
      while((column_counter++ < PAL_HD44780_NO_OF_COLUMNS) && *S)
        {
          is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
          PalHd44780_ByteWrite(*S++, PAL_HD44780_DAT);
          retVal++;
        }

      row_counter++;
      column_counter = 0;
      PalHd44780_ByteWrite(PalHd44780_Row_Addr[row_counter], PAL_HD44780_INS);
    }

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 16, 2012, 7:19:16 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalHd44780_LoadCustomFont(PalHd44780_FontPlotType *font_ptr, uint8_t len)
{
  Std_ReturnType retVal = E_NOT_OK;
  uint8_t cgram_addr = 0;

  if(len <= 8)
    {
      /* TODO: Check dissassembly if len*8 is calculated statically or
       * dynamically. If latter, change code to make former (improve speed).
       */
      while(cgram_addr < (len * 8))
        {
          PalHd44780_LoadCGRAM(font_ptr, cgram_addr);
          font_ptr += 8;
          cgram_addr += 8;
        }

      retVal = E_OK;
    }
  /* else not required (len <= 8) */

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/**@cond ***********************************************************************
 * TODO: Update all comment fields and delete this line.
 * MOD: For functions with project scope, remove 'static' keyword and declare
 * prototype in hd44780.h
 * -------------------------------------------------------------------- @endcond
 * @fn          Std_ReturnType function_name(TYPE parameter1, TYPE parameter2)
 * @return      Describe the function's return value here.
 * @param       parameter1 Describe the function's 1st parameter here.
 * @param       parameter2 Describe the function's 2nd parameter here.
 * @author      Ashwin
 * @date        Feb 12, 2012, 9:42:32 PM
 * @brief	Provide a brief description of the module here (Single line).
 * @details	Provide a detailed description of the module here (Multi-line).
 * @pre         Mention any preconditions required to use this function.
 * @post        Mention any postcondition required to use this function.
 * @bug         List any bugs in this module.
 * @note        List any odd modes while using this function.
 * @warning     List any warnings against using the objects of this function.
 *******************************************************************************
 */

Std_ReturnType
PalHd44780_15x16Putc(PalHd44780_FontIndexType *font_index, char character)
{
  Std_ReturnType retVal = E_NOT_OK;

  uint8_t X, Y, Xtemp;
  uint32_t font_index_ptr, font_width_1, font_width_2;

  PalHd44780_GetXY(&X, &Y);

  if((Y + 2) < PAL_HD44780_NO_OF_COLUMNS)
    {
      PalHd44780_GoToXY(X, Y);

      if(' ' == character)
        {
          PalHd44780_Putc(0x10);
          PalHd44780_GoToXY( (X+1), Y );
          PalHd44780_Putc(0x10);
        }
      else
        {
          font_index_ptr = ((( (uint32_t)character - '0') * 6) + ( (uint32_t)character - '0'));
          font_width_1 = font_index[font_index_ptr];
          font_width_2 = font_width_1;
          font_index_ptr++;

          while(font_width_1--)
            {
              is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
              PalHd44780_Putc(font_index[font_index_ptr++]);
            }

          PalHd44780_GoToXY( (X+1), Y );

          while(font_width_2--)
            {
              is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
              PalHd44780_Putc(font_index[font_index_ptr++]);
            }
        }

      PalHd44780_GetXY(&Xtemp, &Y);
      PalHd44780_GoToXY(X, Y);

      retVal = E_OK;
    }
  /* else not required [((Y + 2) > PAL_HD44780_NO_OF_COLUMNS)] */

  return (retVal);
}

Std_ReturnType
PalHd44780_15x32Putc(PalHd44780_FontIndexType *font_index, char character)
{
  Std_ReturnType retVal = E_NOT_OK;

  uint8_t X, Y, Xtemp;
  uint32_t font_index_ptr, font_width_1, font_width_2, font_width_3, font_width_4;

  PalHd44780_GetXY(&X, &Y);

  if((Y + 2) < PAL_HD44780_NO_OF_COLUMNS)
    {
      PalHd44780_GoToXY(X, Y);

      if(' ' == character)
        {
          PalHd44780_Putc(0x10);
          PalHd44780_GoToXY( (X+1), Y );
          PalHd44780_Putc(0x10);
          PalHd44780_GoToXY( (X+2), Y );
          PalHd44780_Putc(0x10);
          PalHd44780_GoToXY( (X+3), Y );
          PalHd44780_Putc(0x10);
        }
      else
        {
          font_index_ptr = ((( (uint32_t)character - '0') * 12) + ( (uint32_t)character - '0'));
          font_width_1 = font_index[font_index_ptr];
          font_width_4 = font_width_3 = font_width_2 = font_width_1;
          font_index_ptr++;

          while(font_width_1--)
            {
              is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
              PalHd44780_Putc(font_index[font_index_ptr++]);
            }

          PalHd44780_GoToXY( (X+1), Y );

          while(font_width_2--)
            {
              is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
              PalHd44780_Putc(font_index[font_index_ptr++]);
            }

          PalHd44780_GoToXY( (X+2), Y );

          while(font_width_3--)
            {
              is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
              PalHd44780_Putc(font_index[font_index_ptr++]);
            }

          PalHd44780_GoToXY( (X+3), Y );

          while(font_width_4--)
            {
              is_PalHd44780_Busy(PAL_HD44780_BF_CHECK_TIMEOUT);
              PalHd44780_Putc(font_index[font_index_ptr++]);
            }
        }

      PalHd44780_GetXY(&Xtemp, &Y);
      PalHd44780_GoToXY(X, Y);

      retVal = E_OK;
    }
  /* else not required [((Y + 2) > PAL_HD44780_NO_OF_COLUMNS)] */

  return (retVal);
}

uint8_t
PalHd44780_15x32Puts( char* S )
{
  uint8_t retVal = 0;
  uint8_t current_addr;
  uint8_t row_counter, column_counter;

  PalHd44780_GetXY(&row_counter, &column_counter);

  while((row_counter < (PAL_HD44780_NO_OF_ROWS) ) && *S)
    {
      while((column_counter++ < PAL_HD44780_NO_OF_COLUMNS) && *S)
        {
          PalHd44780_15x32Putc( PalHd44780_15x16FontIndex, *S++ );
          retVal++;
        }

      row_counter += 4;
      column_counter = 0;
      PalHd44780_ByteWrite(PalHd44780_Row_Addr[row_counter], PAL_HD44780_INS);
    }

  return (retVal);
}

/** End of function_name ************ Copyright (C) 2012 Afflatus Techtronics */

/** END OF FILE ********************* Copyright (C) 2012 Afflatus Techtronics */
